package data.repository;

import java.io.Serializable;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;

public class Repository<T> implements IRepository<T> {
	private Session session;

	public Repository() {
		this.session =  HibernateUtil.getSessionFactory().openSession();
	}

	@SuppressWarnings("unchecked")
	public final List<T> getAll(final Class<T> clazz) throws RepositoryException {

		try {
			return (this.session.createCriteria(clazz).list());
		} catch (final HibernateException e) {
			throw new RepositoryException(e);
		}
	}
	
	@SuppressWarnings("unchecked")
	public final List<T> getAll(final String queryExpression,
	        final QueryParameter... parameters) throws RepositoryException {

		try {
			final Query query = this.session.createQuery(queryExpression);
			
			for (QueryParameter queryParameter : parameters) {
				query.setParameter(queryParameter.getName(), queryParameter.getValue());
			}
			
			return query.list();

		} catch (final HibernateException e) {
			throw new RepositoryException(e);
		}
	}
	
	@SuppressWarnings("unchecked")
	public final T get(final Class<T> clazz, final Serializable id) throws RepositoryException {

		try {
			return ((T) this.session.get(clazz, id));
		} catch (final HibernateException e) {
			throw new RepositoryException(e);
		}
	}

	@SuppressWarnings("unchecked")
	public final T get(final String queryExpression,
	        final QueryParameter... parameters) throws RepositoryException {

		try {
			final Query query = this.session.createQuery(queryExpression);
			
			for (QueryParameter queryParameter : parameters) {
				query.setParameter(queryParameter.getName(), queryParameter.getValue());
			}
			
			return (T)query.uniqueResult();

		} catch (final HibernateException e) {
			throw new RepositoryException(e);
		}
	}
	
	public final boolean exists(final Class<T> clazz, final Serializable id) throws RepositoryException {
		return this.get(clazz, id) != null;
	}
	
	public final void saveOrUpdate(final T instance) throws RepositoryException {

		try {
			this.session.beginTransaction();
			this.session.saveOrUpdate(instance);
		} catch (final HibernateException e) {
			this.session.getTransaction().rollback();
			throw new RepositoryException(e);
		} finally {
			this.session.getTransaction().commit();
		}
	}

	public final void delete(final T instance) throws RepositoryException {
		try {
			this.session.delete(instance);
		} catch (final HibernateException e) {
			throw new RepositoryException(e);
		}
	}
}
